package com.dock.classin.service.impl;

import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.request.AlipayUserInfoShareRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.dock.classin.base.PayPalVo;
import com.dock.classin.base.Paypal;
import com.dock.classin.mapper.PaypalMapper;
import com.dock.classin.service.ApiService;
import com.dock.classin.service.PayPalService;
import com.dock.classin.utils.*;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

@Service
public class ApiServiceImpl implements ApiService {
    Logger logger = Logger.getLogger("ApiServiceImpl");
    @Value("${paypal.mid}")
    private String mid;
    @Value("${paypal.tid}")
    private String tid;
    @Value("${paypal.AppId}")
    private String AppId;
    @Value("${paypal.AppKey}")
    private String AppKey;
    @Value("${paypal.PRIVATE_KEY}")
    private String PRIVATE_KEY;
    @Value("${paypal.ALIPAY_PUBLIC_KEY}")
    private String ALIPAY_PUBLIC_KEY;
    @Value("${paypal.ZFB_APPID}")
    private String ZFB_APPID;
    @Value("${paypal.AccessTokenUrl}")
    private String AccessTokenUrl;
    @Value("${paypal.placeAnOrderUrlVX_XCX}")
    private String placeAnOrderUrlVX_XCX;
    @Value("${paypal.query_XCX}")
    private String query_XCX;
    @Value("${paypal.refund_XCX}")
    private String refund_XCX;
    @Value("${paypal.refund_query_XCX}")
    private String refund_query_XCX;
    @Value("${paypal.msgSrcId}")
    private String msgSrcId;
    @Value("${paypal.ZFB_XIADAN}")
    private String ZFB_XIADAN;
    @Value("${paypal.pay_YunZhiFu}")
    private String pay_YunZhiFu;
    @Autowired
    private PayPalService payPalService;

    Cache<String, String> fifoCache = CacheUtil.newFIFOCache(1);


    @Override
    public String pay(PayPalVo payPalVo) throws JSONException {
        Map<String, Object> paramMap = new HashMap<>();
        //报文请求时间字符串 是 格式yyyy-MM-dd HH:mm:ss
        String timestamp = DateUtils.getTime();
        String nonce = msgSrcId + UUIDUtils.getUUID24();
        paramMap.put("requestTimestamp", timestamp);
        //商户订单号
        paramMap.put("merOrderId", nonce);
        //商户号
        paramMap.put("mid", mid);
        //终端号
        paramMap.put("tid", tid);
        //机构商户号
        paramMap.put("instMid", "MINIDEFAULT");
        String tradeType = "MINI";
        //回调地址
        paramMap.put("notifyUrl", "https://classin.tbibss.gamification.org.cn/pay/pal/zhifuhuidiao");
        String url = "";
        if ("WX".equals(payPalVo.getType())) {
            paramMap.put("subOpenId", payPalVo.getOpenId());
            url = placeAnOrderUrlVX_XCX;
        }
        if ("ZFB".equals(payPalVo.getType())) {
            String userId = getZFBUserid(payPalVo.getCode());
            paramMap.put("userId", userId);
            url = ZFB_XIADAN;
        }
        if ("YZF".equals(payPalVo.getType())) {
            url = pay_YunZhiFu;
            tradeType = "UP_WX_MINI";
            paramMap.put("invokeScene", "03");
        }
        paramMap.put("tradeType", tradeType);
        paramMap.put("subAppId", "wxd28a030c676dc743");

        //支付总金额
        paramMap.put("totalAmount", payPalVo.getTxnAmt());
        JSONObject json = new JSONObject(paramMap);
        System.out.println("下单传参：" + json.toString());
        HttpRequest request = HttpRequest.post(url);
        request.header("Content-Type", "application/json");
//        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=78a728b5e1364498993d84929f8e816b");
        String token = "";
        token = fifoCache.get("token");
        if (StringUtils.isEmpty(token)) {
            token = token();
            fifoCache.put("token", token, DateUnit.SECOND.getMillis() * 600);
        }

        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=" + token);
        String body = JSONUtil.toJsonPrettyStr(paramMap);
        // 设置请求体数据
        request.body(body);
        // 发送请求并获取响应
        HttpResponse response = request.execute();
        int responseCode = response.getStatus();
        System.out.println("Response Code: " + responseCode);
        // 读取响应数据
        String responseBody = response.body();

        // 打印响应数据
        System.out.println("Response: " + responseBody);
        ExceutorUtil.getExcutor().execute(() -> {
            Paypal paypal = new Paypal();
            paypal.setMerOrderId(nonce);
            paypal.setUserName(payPalVo.getUserName());
            paypal.setStatus("未支付");
            paypal.setBaomingcode(payPalVo.getBaomingcode());
            paypal.setDingdan_code(payPalVo.getDingdan_code());
            paypal.setPhone(payPalVo.getPhone());
            paypal.setName(payPalVo.getName());
            paypal.setTotalAmount(payPalVo.getTxnAmt());
            paypal.setXiadanTime(DateUtils.getNowDate());
            paypal.setType(payPalVo.getType());
            paypal.setText("前端传值：" + JSON.toJSONString(payPalVo) + "。返回报文：" + responseBody + "。下单请求报文" + json.toString());
            payPalService.insertPaypal(paypal);
        });
        return responseBody;
    }

    @Override
    public String refund(String dingdan_code,Paypal paypal) throws JSONException {
        paypal.setTuikuan_shenqing_time(DateUtils.getNowDate());
        payPalService.updatePaypal(paypal);

        Map<String, Object> paramMap = new HashMap<>();
        // 使用form传参，不需要自己拼接一长串内容
        String timestamp = DateUtils.dateTimeNow();
        //报文请求时间
        paramMap.put("requestTimestamp", timestamp);
        //商户号
        paramMap.put("mid", mid);
        //终端号
        paramMap.put("tid", tid);
        //商户订单号
        paramMap.put("merOrderId", paypal.getMerOrderId());
        //支付订单号
        paramMap.put("targetOrderId", paypal.getTargetOrderId());
        //要退货的金额
        paramMap.put("refundAmount", paypal.getTotalAmount());
        HttpRequest request = HttpRequest.post(refund_XCX);
        request.header("Content-Type", "application/json");
//        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=78a728b5e1364498993d84929f8e816b");
        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=" + token() );
        String body = JSONUtil.toJsonPrettyStr(paramMap);
        // 设置请求体数据
        request.body(body);
        // 发送请求并获取响应
        HttpResponse response = request.execute();
        int responseCode = response.getStatus();
        System.out.println("Response Code: " + responseCode);
        // 读取响应数据
        String responseBody = response.body();
        // 打印响应数据
        System.out.println("Response: " + responseBody);
        paypal.setTuikuan_text(responseBody);
        payPalService.updatePaypal(paypal);
        return responseBody;
    }

    @Override
    public String refund_query(String merOrderId, String targetOrderId) throws JSONException {
        Map<String, Object> paramMap = new HashMap<>();
        // 使用form传参，不需要自己拼接一长串内容
        String timestamp = DateUtils.dateTimeNow();
        //报文请求时间
        paramMap.put("requestTimestamp", timestamp);
        //商户号
        paramMap.put("mid", mid);
        //终端号
        paramMap.put("tid", tid);
        //商户订单号
        paramMap.put("merOrderId", merOrderId);
        paramMap.put("targetOrderId", targetOrderId);
        //业务类型
        paramMap.put("instMid", "MINIDEFAULT");
        HttpRequest request = HttpRequest.post(refund_query_XCX);
        request.header("Content-Type", "application/json");
//        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=78a728b5e1364498993d84929f8e816b");
        request.header("Authorization", "OPEN-ACCESS-TOKEN AccessToken=" + token());
        String body = JSONUtil.toJsonPrettyStr(paramMap);
        // 设置请求体数据
        request.body(body);
        // 发送请求并获取响应
        HttpResponse response = request.execute();
        int responseCode = response.getStatus();
        System.out.println("Response Code: " + responseCode);
        // 读取响应数据
        String responseBody = response.body();
        // 打印响应数据
        System.out.println("Response: " + responseBody);
        return responseBody;
    }

    @Override
    public String zhifuhuidiao(HttpServletRequest request) throws IOException {
        ServletInputStream is = request.getInputStream();
        byte[] bs = new byte[1024];
        int len = -1;
        StringBuilder builder = new StringBuilder();
        while ((len = is.read(bs)) != -1) {
            builder.append(new String(bs, 0, len));
        }
        String s = builder.toString();
        Map<String, String> parameters = new HashMap<>();
        String[] pairs = s.split("&");
        try {
            for (String pair : pairs) {
                int idx = pair.indexOf("=");
                String key = URLDecoder.decode(pair.substring(0, idx), "UTF-8");
                String value = URLDecoder.decode(pair.substring(idx + 1), "UTF-8");
                parameters.put(key, value);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        JSONObject json = new JSONObject(parameters);
        logger.info("回调信息：" + JSON.toJSONString(parameters));
        String merOrderId = parameters.get("merOrderId");
        String targetOrderId = parameters.get("targetOrderId");
        String status = parameters.get("status");
        logger.info("订单号" + merOrderId);
        logger.info("支付号" + targetOrderId);
        logger.info("状态" + status);
        Paypal paypal = new Paypal();
        paypal.setMerOrderId(merOrderId);
        List<Paypal> paypals = payPalService.selectPaypalList(paypal);
        if ("未支付".equals(paypals.get(0).getStatus())) {
            if ("TRADE_SUCCESS".equals(status)) {
                if (!paypals.get(0).getStatus().equals(status)) {
                    paypal.setId(paypals.get(0).getId());
                    paypal.setTargetOrderId(targetOrderId);
                    paypal.setStatus("支付成功");
                    paypal.setPaypalTime(DateUtils.getNowDate());
                    payPalService.updatePaypal(paypal);
                    System.out.println("支付完成回调：" + json.toString());
                }
            }
        }
        if ("支付成功".equals(paypals.get(0).getStatus())) {
            if ("TRADE_REFUND".equals(status)) {
                if (!paypals.get(0).getStatus().equals(status)) {
                    paypal.setId(paypals.get(0).getId());
                    paypal.setTargetOrderId(targetOrderId);
                    paypal.setStatus("已退款");
                    paypal.setTuikuan_time(DateUtils.getNowDate());
                    payPalService.updatePaypal(paypal);
                    System.out.println("退款回调" + json.toString());
                }
            }
        }
        return "成功";
    }

    /***
     * 支付宝用户授权，获取用户信息
     * @author Mark
     * @param code
     * @return
     */
    public String getZFBUserid(String code) {

        //根据code获取accessToken
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                ZFB_APPID, PRIVATE_KEY, "json",
                "GBK", ALIPAY_PUBLIC_KEY, "RSA2");
        AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
        request.setGrantType("authorization_code");
        request.setCode(code);
        request.setRefreshToken("201208134b203fe6c11548bcabd8da5bb087a83b");
        AlipaySystemOauthTokenResponse response = null;
        String userid = "";
        try {
            response = alipayClient.execute(request);
        } catch (AlipayApiException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        if (response.isSuccess()) {
            //根据accessToken获取用户信息
            AlipayClient alipayClients = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do",
                    ZFB_APPID, PRIVATE_KEY, "json",
                    "GBK", ALIPAY_PUBLIC_KEY, "RSA2");
            AlipayUserInfoShareRequest req = new AlipayUserInfoShareRequest();
            AlipayUserInfoShareResponse res = null;
            try {
                res = alipayClients.execute(req, response.getAccessToken());
            } catch (AlipayApiException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(res.getUserId());
            userid = res.getUserId();
        }

        return userid;
    }

    public String token() throws JSONException {
        Map<String, Object> paramMap=new HashMap<>();
        String timestamp=DateUtils.dateTimeNow();
        String nonce=UUIDUtils.getUUID36();
        nonce=nonce+nonce+nonce+nonce;
        paramMap.put("appId",AppId);
        paramMap.put("timestamp", timestamp);
        paramMap.put("nonce",nonce);
        paramMap.put("signMethod","SHA256");
        String signature=EncryptUtils.sha256(AppId+timestamp+nonce+AppKey);
        paramMap.put("signature",signature);
        // 创建 POST 请求
        HttpRequest request = HttpRequest.post(AccessTokenUrl);
        // 设置请求头部
        request.header("Content-Type", "application/json");
        String body = JSONUtil.toJsonPrettyStr(paramMap);
        // 设置请求体数据
        request.body(body);

        // 发送请求并获取响应
        HttpResponse response = request.execute();

        // 获取响应状态码
        int responseCode = response.getStatus();
        System.out.println("Response Code: " + responseCode);

        // 读取响应数据
        String responseBody = response.body();

        // 打印响应数据
        System.out.println("Response: " + responseBody);

        // 解析JSON字符串
        JSONObject jsonObject = new JSONObject(responseBody);
        // 提取accessToken的值
        String accessToken = jsonObject.getString("accessToken");
        // 输出accessToken的值
        System.out.println("accessToken: " + accessToken);
        return accessToken;
    }

}
